﻿using LModBusRTU;
using LPBToolsLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;

namespace StationNF
{
    /// <summary>
    /// 快速简化协议接受回调函数接口
    /// </summary>
    /// <param name="senderBus">收到数据的总线</param>
    /// <param name="tDatasRecFromBus">收到的数据实体，根据总线不同，存放不同对象，并进行不同处理</param>
    /// <param name="tRspDatasToNet">应答数据，不一定所有总线都会有应答数据</param>
    /// <returns></returns>  
    /// <summary>
    public delegate bool BusRecCallBack(EndPoint SourPoint, object tDatasRecFromBus, out byte[] tRspDatas);

    public interface IFStationsServer
    {
        Recorder_Error SysErr { get; set; }
        Recorder_RunLog RunLog { get; set; }
        int StationCount { get; }
        string[] StationsIDList { get; }
        int CommandTOutMs { get; set; }
        IFDExCommunicater getCommunicater(string StationID);
        IFStation getStation(string StationID);
        void CloseAll();
    }

    public class StationsServer: IFStationsServer
    {
        public static IFStationsServer ServerIF { get; protected set; } = null;
        //public static JSONINISettings StationServerCFG { get; set; } = null;
        public Recorder_Error SysErr { get; set; } = null;
        public Recorder_RunLog RunLog { get; set; } = null;
        /// <summary>
        /// 线程锁字符串
        /// </summary>
        private static string sUniquKey = "StationsServer_20221203" + Guid.NewGuid().ToString();
        /// <summary>
        /// 线程锁
        /// </summary>
        private Mutex thdMutex { get; } = new Mutex(false, sUniquKey);

        private bool iThdRun = false;
        private Thread thdMain = null;
        /// <summary>
        /// 工作站对象字典
        /// </summary>
        protected Dictionary<string, IFDExCommunicater> tStationsList { get; } = new Dictionary<string, IFDExCommunicater>();
        public void CloseAll()
        {
            ServerIF = null;
            iThdRun = false;
            Thread.Sleep(20);
        }
        #region 反馈在线工作站及通讯通道情况
        /// <summary>
        /// 当前在线工作站数量
        /// </summary>
        public int StationCount { get { return tStationsList.Count; } }
        /// <summary>
        /// 当前在线的工作站列表
        /// </summary>
        public string[] StationsIDList { get { return tStationsList.Keys.ToArray(); } }
        /// <summary>
        /// 根据提供的StationID，返回对应的通讯接口及工作站
        /// </summary>
        /// <param name="StationID"></param>
        /// <returns></returns>
        public IFStation getStation(string StationID)
        {
            thdMutex.WaitOne();
            try
            {
                if (tStationsList.ContainsKey(StationID)&&(tStationsList[StationID]!=null))
                    return tStationsList[StationID].Station;
            }
            finally
            {
                thdMutex.ReleaseMutex();
            }
            return null;
        }


        public IFDExCommunicater getCommunicater(string StationID)
        {
            thdMutex.WaitOne();
            try
            {
                if (tStationsList.ContainsKey(StationID))
                    return tStationsList[StationID];
            }
            finally
            {
                thdMutex.ReleaseMutex();
            }
            return null;
        }

        public bool getStation(string StationID,out IFDExCommunicater tCommunicater)
        {
            tCommunicater = null;
            thdMutex.WaitOne();
            try
            {
                if (tStationsList.ContainsKey(StationID))
                    tCommunicater= tStationsList[StationID];
            }
            finally
            {
                thdMutex.ReleaseMutex();
            }
            return tCommunicater!=null;
        }
        #endregion
              
        public StationsServer()
        {
            ServerIF = this;
            thdMain = new Thread(thdMainRun);
            iThdRun = true;
            thdMain.Start();
        }

        public int CommandTOutMs { get; set; } = 1000;

        private void thdMainRun()
        {
            while (iThdRun)
                try
                {
                    List<string> tDelStaID = new List<string>();
                    thdMutex.WaitOne();
                    try
                    {
                        foreach (KeyValuePair<string, IFDExCommunicater> item in tStationsList)
                        {
                            if ((DateTime.Now - item.Value.LastPacketTime).TotalMilliseconds > (CommandTOutMs * 3))
                            {
                                item.Value.CloseAll();
                                tDelStaID.Add(item.Key);
                            }
                        }
                        foreach (string StaID in tDelStaID)
                            tStationsList.Remove(StaID);
                    }
                    finally
                    {
                        thdMutex.ReleaseMutex();
                    }
                }

                catch (Exception ex)
                {
                    SysErr?.setRecord(ex);
                }
                finally
                {
                    Thread.Sleep(10);
                }
        }
        /// <summary>
        /// 接收网络层收到数据，进行相关处理
        /// </summary>
        /// <param name="senderBus">收到数据的总线，不能为空</param>
        /// <param name="tDatasRecFromBus">收到的数据载体，根据总线不同，进行不同转换处理</param>
        /// <param name="tRspDatas">应答的数据，不一定所有总线都在此处应答</param>
        /// <returns></returns>
        public bool doRecDatas(EndPoint SourPoint, object tDatasRecFromBus, out byte[] tRspDatas)
        {
            tRspDatas = null;
            if ((tDatasRecFromBus != null))
            {
                try
                {
                    // 1、根据收到的数据生成交换数据节点
                    DExPacket tRecEDatas = (DExPacket)tDatasRecFromBus;
                    DExRespon tRspEDatas = null;
                    // 成功识别收到的数据
                    if ((tRecEDatas != null) && tRecEDatas.isReady)
                    {
                        // 2、根据数据信息查找相关工作站对象进行处理
                        string sDestStaID = tRecEDatas.StatioinID;
                        IFDExCommunicater tNewStaCommunicate = null;
                        // 线程安全
                        thdMutex.WaitOne();
                        try
                        {
                            // 判断是否已经存在工作站对象
                            if (!tStationsList.ContainsKey(sDestStaID))
                            {
                                PLCStation tStation = new PLCStation(sDestStaID);
                                // 创建新的节点
                                DExPacketCommunicate tStaCommunicate = new DExPacketCommunicate(SourPoint, sDestStaID, tStation);
                                tNewStaCommunicate = tStaCommunicate;
                                if (tNewStaCommunicate != null)
                                {
                                    tStation.OnWriteRegValues = tStaCommunicate.writeToPLCCallBack;
                                    tStationsList.Add(sDestStaID, tNewStaCommunicate);
                                    tNewStaCommunicate.CommandTOutMs = CommandTOutMs;
                                }
                                RunLog?.setRecord(new Record("Create new station:" + sDestStaID));
                            }
                            else
                            {
                                tNewStaCommunicate = (IFDExCommunicater)tStationsList[sDestStaID];
                            }
                        }
                        finally
                        {
                            thdMutex.ReleaseMutex();
                        }
                        if (tNewStaCommunicate != null)
                            // 3、调用工作站对象处理收到的数据，并保存应答数据
                            tRspEDatas = tNewStaCommunicate.receNewPacket(tRecEDatas);
                        byte[] tTmpBuf = null;

                        // 4、处理应答数据，将其转换为数据流包，并返回给网络Socket层返回给终端设备
                        if (tRspEDatas != null && tRspEDatas.getResponDatas(out tTmpBuf)
                            && tTmpBuf != null)
                        {
                            List<byte> tRspBuf = new List<byte>(tTmpBuf);
                            tRspDatas = tRspBuf.ToArray();
                            return true;
                        }
                    }
                }
                catch (Exception ex)
                {
                    SysErr?.setRecord(ex);
                }
            }
            return false;
        }

    }
}
